package lu.uni.adtool.ui;

import lu.uni.adtool.Options;
import lu.uni.adtool.adtree.ADTreeForGui;
import lu.uni.adtool.adtree.ADTreeNode;
import lu.uni.adtool.domains.Domain;
import lu.uni.adtool.domains.DomainFactory;
import lu.uni.adtool.domains.ValueAssignement;
import lu.uni.adtool.domains.predefined.IntMinMax;
import lu.uni.adtool.domains.predefined.Parametrized;
import lu.uni.adtool.domains.rings.BoundedInteger;
import lu.uni.adtool.ui.printview.JPrintPreviewDialog;
import lu.uni.adtool.ui.texts.ButtonTexts;
import lu.uni.adtool.ui.texts.ToolTipTexts;
import net.infonode.docking.*;
import net.infonode.docking.mouse.DockingWindowActionMouseButtonListener;
import net.infonode.docking.properties.RootWindowProperties;
import net.infonode.docking.theme.*;
import net.infonode.docking.util.DockingUtil;
import net.infonode.docking.util.MixedViewHandler;
import net.infonode.docking.util.PropertiesUtil;
import net.infonode.docking.util.ViewMap;
import net.infonode.util.Direction;

import javax.swing.*;
import javax.swing.text.DefaultEditorKit;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.List;

/**
 * A class containing the main window of application.
 *
 * @author Piot Kordy
 * @version
 */
public class MainWindow extends Frame
{
  private static final int     ICON_SIZE  = 8;
  /**
     * This adapter handles Mouse over messages on toolbar buttons and
     * menu items.
     */
  private MouseHandler mouseHandler;
  private static ADAction fileNew;
  private static ADAction fileOpen;
  private static ADAction fileSave;
  private static ADAction fileExample;
  private static ADAction fileExportToPdf;
  private static ADAction fileExportToLatex;
  private static ADAction fileExportToPng;
  private static ADAction fileExportToJpg;
  private static ADAction filePrint;
  private static ADAction filePrintPreview;
  private static ADAction fileExit;
  /**
   * Status bar
   */
  private JLabel status;
  /**
   * Saved layout in memory.
   */
  private byte[] layout;
  /**
   * Class for handling displaying dialogs for saving/loading files.
   */
  private FileHandler fh;

  /**
   * The one and only root window.
   */
  private RootWindow           rootWindow;

  /**
   * The application frame.
   */
  private JFrame               frame      = new JFrame(
                                              "Attack Defense Tree Tool");
  /**
   * An array of the static views.
   */
  private View[]               views      = new View[4];

  /**
   * Contains the dynamic views that has been added to the root window.
   */
  private HashMap<Integer,DynamicView> dynamicViews = new HashMap<Integer,DynamicView>();

  /**
   * Contains all the static views.
   */
  private ViewMap              viewMap    = new ViewMap();

  /**
   * The windows menu items.
   */
  private JMenuItem[] windowsItems = new JMenuItem[views.length];
  /**
   * The Attribute Domains menu.
   */
  private JMenu attrDomainsMenu;
  /**
   * The currently applied docking windows theme
   */
  private DockingWindowsTheme currentTheme = new ShapedGradientDockingTheme();
  private ADTreeCanvas lastFocused;
  /**
   * In this properties object the modified property values for close buttons
   * etc. are stored. This object is cleared when the theme is changed.
   */
  private RootWindowProperties properties = new RootWindowProperties();

  /**
   * Sets the lastFocused for this instance.
   *
   * @param lastFocused The lastFocused.
   */
  public void setLastFocused(ADTreeCanvas lastFocused)
  {
    this.lastFocused = lastFocused;
    if (lastFocused instanceof DomainCanvas){
      ((ValuationView)views[2].getComponent()).assignCanvas((DomainCanvas)lastFocused);
      ((DetailsView)views[3].getComponent()).assignCanvas((DomainCanvas)lastFocused);
    }
    else if (lastFocused == null){
    //else {
      ((ValuationView)views[2].getComponent()).assignCanvas(null);
      ((DetailsView)views[3].getComponent()).assignCanvas(null);
    }
  }

  /**
   * Gets the views for this instance.
   *
   * @return The views.
   */
  public View[] getViews()
  {
    return this.views;
  }

  /**
   * Gets the views for this instance.
   *
   * @param index The index to get.
   * @return The views.
   */
  public View getViews(int index)
  {
    return this.views[index];
  }

  /**
   * Gets the lastFocused for this instance.
   *
   * @return The lastFocused.
   */
  public ADTreeCanvas getLastFocused()
  {
    return this.lastFocused;
  }

  /**
   * A dynamically created view containing an id.
   */
  private static class DynamicView extends View {
    static final long serialVersionUID = 4127190623311867764L;
    private int id;

    /**
     * Constructor.
     *
     * @param title     the view title
     * @param icon      the view icon
     * @param component the view component
     * @param id        the view id
     */
    DynamicView(String title, Icon icon, Component component, int id) {
      super(title, icon, component);
      this.id = id;
    }

    /**
     * Returns the view id.
     *
     * @return the view id
     */
    public int getId() {
      return id;
    }
  }
  /**
   * Constructs a new instance.
   */
  public MainWindow()
  {
    createActions();
    createRootWindow();
    restoreDefaultLayout();
    showFrame();
  }

  /**
   * Creates the status bar.
   *
   * @return JLabel that holds the text of a status bar.
   */
  private JLabel createStatusBar()
  {
    status = new JLabel("Ready...");
    status.setBorder(BorderFactory.createEtchedBorder());

    return status;
  }

  /**
   * Creates a view component containing the specified text.
   *
   * @param text
   *          the text
   * @return the view component
   */

  private static JComponent createViewComponent(final String text)
  {
    final StringBuffer sb = new StringBuffer();

    for (int j = 0; j < 100; j++) {
      sb.append(text + ". This is line " + j + "\n");
    }

    return new JScrollPane(new JTextArea(sb.toString()));
  }
  /**
   * Update the floating window by adding a menu bar and a status label if menu option is choosen.
   *
   * @param fw the floating window
   */
  private void updateFloatingWindow(FloatingWindow fw) {
    // Only update with if menu is selected
    //if (enableMenuAndStatusLabelMenuItem.isSelected()) {
      // Create a dummy menu bar as example
      //JMenuBar bar = new JMenuBar();
      //bar.add(new JMenu("Menu 1")).add(new JMenuItem("Menu 1 Item 1"));
      //bar.add(new JMenu("Menu 2")).add(new JMenuItem("Menu 2 Item 1"));

      //// Set it in the root pane of the floating window
      //fw.getRootPane().setJMenuBar(bar);

      //// Create and add a status label
      //JLabel statusLabel = new JLabel("I'm a status label!");

      //// Add it as the SOUTH component to the root pane's content pane. Note that the actual floating
      //// window is placed in the CENTER position and must not be removed.
      //fw.getRootPane().getContentPane().add(statusLabel, BorderLayout.SOUTH);
    //}
  }
  /**
   * Returns the next available dynamic view id.
   *
   * @return the next available dynamic view id
   */
  private int getDynamicViewId() {
    int id = 0;

    while (dynamicViews.containsKey(new Integer(id)))
      id++;

    return id;
  }
  /**
   * Update view menu items and dynamic view map.
   *
   * @param window the window in which to search for views
   * @param added  if true the window was added
   */
  private void updateViews(DockingWindow window, boolean added) {
    if (window instanceof View) {
      if (window instanceof DynamicView) {
        if (added){
          dynamicViews.put(new Integer(((DynamicView) window).getId()), (DynamicView)window);
        }
        else{
          dynamicViews.remove(new Integer(((DynamicView) window).getId()));
        }
        createAttrDomainMenu(attrDomainsMenu);
      }
      else { //enable menu?
        for (int i = 0; i < views.length; i++)
          if (views[i] == window && windowsItems[i] != null)
            windowsItems[i].setEnabled(!added);
      }
    }
    else {
      for (int i = 0; i < window.getChildWindowCount(); i++)
        updateViews(window.getChildWindow(i), added);
    }
  }

  private void createRootWindow()
  {
    ADTreeForGui tree = new ADTreeForGui(new ADTreeNode());

      System.out.println(this.getClass().getResource("/").getPath());
    views[0] = new View("ADTree Edit", new ImageIcon(this.getClass()
        .getResource("/icons/tree_16x16.png")), new ADTreeView(tree, this));
    ADTreeCanvas canvas = ((ADTreeView)views[0].getComponent()).getCanvas();
    views[1] = new View("ADTerm Edit", new ImageIcon(this.getClass()
        .getResource("/icons/viewTree_16x16.png")), new ADTermView(canvas));
    views[2] = new View("Valuations View", new ImageIcon(this.getClass()
        .getResource("/icons/table_16x16.png")), new ValuationView());
    views[3] = new View("Domain Details View", new ImageIcon(this.getClass()
        .getResource("/icons/eyes_16x16.png")), new DetailsView());
    for (int i = 0; i < views.length; i++) {
      viewMap.addView(i, views[i]);
    }
    MixedViewHandler handler = new MixedViewHandler(viewMap, new ViewSerializer() {
      public void writeView(View view, ObjectOutputStream out) throws IOException {
        int id = ((DynamicView) view).getId();
        out.writeInt(id);
        if (view.getComponent() instanceof DomainView){
          Domain d = ((DomainCanvas)((DomainView)view.getComponent()).getCanvas()).getDomain();
          out.writeObject(DomainFactory.getClassName(d));
        }
      }

      public View readView(ObjectInputStream in) throws IOException {
        int id = in.readInt();
        try{
          String domainName = (String)in.readObject();
          return getDynamicView(id,DomainFactory.createFromString(domainName));
        }
        catch(ClassNotFoundException e){
          return null;
        }
      }
    });
    rootWindow = DockingUtil.createRootWindow(viewMap, handler, true);
    // Set gradient theme. The theme properties object is the super object of our properties object, which
    // means our property value settings will override the theme values
    properties.addSuperObject(currentTheme.getRootWindowProperties());

    // Our properties object is the super object of the root window properties object, so all property values of the
    // theme and in our property object will be used by the root window
    rootWindow.getRootWindowProperties().addSuperObject(properties);

    // Enable the bottom window bar
    rootWindow.getWindowBar(Direction.DOWN).setEnabled(true);
    // Add a listener which shows dialogs when a window is closing or closed.
    rootWindow.addListener(new DockingWindowAdapter() {
      public void windowAdded(DockingWindow addedToWindow, DockingWindow addedWindow) {
        updateViews(addedWindow, true);

        // If the added window is a floating window, then update it
        if (addedWindow instanceof FloatingWindow)
          updateFloatingWindow((FloatingWindow) addedWindow);
      }

      public void windowRemoved(DockingWindow removedFromWindow, DockingWindow removedWindow) {
        updateViews(removedWindow, false);
      }

      public void windowClosing(DockingWindow window) throws OperationAbortedException {
        // Confirm close operation
        if (window.getChildWindow(0)instanceof DynamicView){
          if (JOptionPane.showConfirmDialog(frame, "Really close window '" + window + "'?") != JOptionPane.YES_OPTION){
            throw new OperationAbortedException("Window close was aborted!");
          }
          Component c = ((DynamicView)window.getChildWindow(0)).getComponent();
          if(c instanceof DomainView) {
            ((DomainView<?>)c).onClose();
          }
        }
      }

      public void windowUndocking(DockingWindow window) throws OperationAbortedException {
        // Confirm undock operation
        //if (JOptionPane.showConfirmDialog(frame, "Really undock window '" + window + "'?") != JOptionPane.YES_OPTION)
          //throw new OperationAbortedException("Window undock was aborted!");
      }

    });

    // Add a mouse button listener that closes a window when it's clicked with the middle mouse button.
    rootWindow.addTabMouseButtonListener(DockingWindowActionMouseButtonListener.MIDDLE_BUTTON_CLOSE_LISTENER);
  }
 
  /**
   * Create all actions used in application.
   */
  private void createActions()
  {

    fileNew = new ADAction(ButtonTexts.NEW) {
       public void actionPerformed(final ActionEvent e) {
        ((ADTreeView)views[0].getComponent()).getCanvas().newTree();
       }
    };
    fileNew.setMnemonic(KeyEvent.VK_N);
    fileNew.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N,
        InputEvent.ALT_MASK));
    // fileNew.setSmallIcon(new ImageIcon(this.getClass().getResource("/icons/new.png")));
    fileNew.setToolTip(ToolTipTexts.NEW);

    fileOpen = new ADAction(ButtonTexts.OPEN) {
       public void actionPerformed(final ActionEvent e) {
         loadTree();
       }
    };
    fileOpen.setMnemonic(KeyEvent.VK_O);
    fileOpen.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O,
        InputEvent.ALT_MASK));
    // fileOpen.setSmallIcon(new ImageIcon(getClass().getResource("/icons/open.png")));

    fileSave = new ADAction(ButtonTexts.SAVE) {
       public void actionPerformed(final ActionEvent e) {
         saveTree();
       }
    };
    fileSave.setMnemonic(KeyEvent.VK_S);
    fileSave.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,
        InputEvent.ALT_MASK));
    // fileSave.setSmallIcon(new ImageIcon(getClass().getResource("/icons/save.png")));

    fileExample = new ADAction("Load Example Tree") {
       public void actionPerformed(final ActionEvent e) {
         loadExample();
       }
    };
    fileExample.setMnemonic(KeyEvent.VK_L);
    fileExample.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L,
        InputEvent.ALT_MASK));
    // fileExample.setSmallIcon(new ImageIcon(getClass().getResource("/icons/treeEx_16x16.png")));

    fileExportToPdf = new ADAction("Pdf") {
       public void actionPerformed(final ActionEvent e) {
         exportTo("pdf");
       }
    };
    fileExportToPdf.setMnemonic(KeyEvent.VK_P);
    //fileExportToPdf.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
        //InputEvent.ALT_MASK));
    // fileExportToPdf.setSmallIcon(new ImageIcon(getClass().getResource("/icons/pdf_16x16.png")));

    fileExportToLatex = new ADAction("LaTeX") {
       public void actionPerformed(final ActionEvent e) {
         exportTo("tex");
       }
    };
    fileExportToLatex.setMnemonic(KeyEvent.VK_L);
    //fileExportToLatex.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
        //InputEvent.ALT_MASK));
    // fileExportToLatex.setSmallIcon(new ImageIcon(getClass().getResource("/icons/tex_16x16.png")));

    fileExportToPng = new ADAction("PNG image") {
       public void actionPerformed(final ActionEvent e) {
         exportTo("png");
       }
    };
    // fileExportToPng.setSmallIcon(new ImageIcon(getClass().getResource("/icons/png_16x16.png")));
    fileExportToPng.setMnemonic(KeyEvent.VK_N);

    fileExportToJpg = new ADAction("JPEG image") {
       public void actionPerformed(final ActionEvent e) {
         exportTo("jpg");
       }
    };
    fileExportToJpg.setMnemonic(KeyEvent.VK_J);
    //fileExportToPng.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N,
        //InputEvent.ALT_MASK));
    // fileExportToJpg.setSmallIcon(new ImageIcon(getClass().getResource("/icons/jpg_16x16.png")));

    filePrintPreview = new ADAction(ButtonTexts.PRINTPREVIEW) {
       public void actionPerformed(final ActionEvent e) {
         printPreview();
       }
    };
    // filePrintPreview.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,
    // InputEvent.ALT_MASK));
    // filePrintPreview.setSmallIcon(new ImageIcon(getClass().getResource("/icons/preview.png")));
    filePrintPreview.setMnemonic(KeyEvent.VK_V);
    filePrintPreview.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P,
        InputEvent.CTRL_MASK));

    filePrint = new ADAction(ButtonTexts.PRINT) {
      public void actionPerformed(final ActionEvent e)
      {
        printCanvas();
      }
    };
    filePrint.setMnemonic(KeyEvent.VK_P);
    filePrint.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P,
        InputEvent.ALT_MASK));
    // filePrint.setSmallIcon(new ImageIcon(getClass().getResource("/icons/print.png")));

    fileExit = new ADAction(ButtonTexts.EXIT) {
       public void actionPerformed(final ActionEvent e) {
        WindowEvent windowClosing = new WindowEvent(frame,
            WindowEvent.WINDOW_CLOSING);
        frame.dispatchEvent(windowClosing);
       }
    };
    fileExit.setMnemonic(KeyEvent.VK_X);
    fileExit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
        InputEvent.CTRL_MASK));
    // fileExit.setSmallIcon(new ImageIcon(getClass().getResource("/icons/exit.png")));
  }

  private void exportTo(String type)
  {
    ADTreeCanvas canvas = ((ADTreeView)views[0].getComponent()).getCanvas();
    if (lastFocused != null) {
      canvas = lastFocused;
    }
    ADTreeNode tempFocus = canvas.getFocused();
    canvas.setFocus(null);
    FileOutputStream out = fh.getExportTreeStream(type);
    if(out!= null){
      if(type.equals("pdf")){
        canvas.createPdf(out);
      }
      else if(type.equals("tex")){
        canvas.createLatex(out);
      }
      else if(type.equals("png")||type.equals("jpg")){
        canvas.createImage(out,type);
      }
    }
    canvas.setFocus(tempFocus);
  }

  private void restoreDefaultLayout()
  {
    rootWindow.setWindow(new SplitWindow(false, 0.37103593f, 
    views[1],
    views[0]));

  }
  private void printPreview()
  {
    ADTreeCanvas canvas = ((ADTreeView)views[0].getComponent()).getCanvas();
    if (lastFocused != null) {
      canvas = lastFocused;
    }
   //int id = getDynamicViewId();
   JPrintPreviewDialog pp = new JPrintPreviewDialog(this,canvas);
   pp.setVisible(true);

  }

  private void printCanvas()
  {
    ADTreeCanvas canvas = ((ADTreeView)views[0].getComponent()).getCanvas();
    if (lastFocused != null) {
      canvas = lastFocused;
    }
    canvas.showPrintDialog(true);
  }
  private void showFrame()
  {
    status = createStatusBar();
    if (isRunningJavaWebStart()){
      fh = new JWSFileHandler(status,this);
    }
    else{
      fh = new FileHandler(status,this);
    }
    mouseHandler = new MouseHandler(status);
    frame.getContentPane().add(createToolBar(), BorderLayout.NORTH);
    frame.getContentPane().add(rootWindow, BorderLayout.CENTER);
    frame.getContentPane().add(status, BorderLayout.SOUTH);
    frame.setJMenuBar(createMenuBar());
    Dimension dim = getScreenSize(0.8,0.4);
    frame.setSize(dim.width,dim.height);
    frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
    frame.addWindowListener(new WindowAdapter()
    {
      public final void windowClosing(final WindowEvent e)
      {
        final JFrame localFrame = (JFrame) e.getSource();

        final int result = JOptionPane.showConfirmDialog(localFrame,
            "Are you sure you want to exit the application?",
            "Exit Application", JOptionPane.YES_NO_OPTION);

        if (result == JOptionPane.YES_OPTION){
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        }
      }
    });
    frame.setVisible(true);
  }

  /**
   * Creates the frame tool bar.
   *
   * @return the frame tool bar
   */
  private JToolBar createToolBar()
  {
     ADToolBar toolbar = new ADToolBar();

     ToolBarButton button;

     button = toolbar.add(fileNew);
     button.addMouseListener(mouseHandler);
     button = toolbar.add(fileOpen);
     button.addMouseListener(mouseHandler);
     button = toolbar.add(fileSave);
     button.addMouseListener(mouseHandler);
     toolbar.addSeparator();
     button = toolbar.add(filePrintPreview);
     button.addMouseListener(mouseHandler);
     toolbar.setTextLabels(true);
     return toolbar;
  }

  /**
   * Creates the frame menu bar.
   *
   * @return the menu bar
   */
  private JMenuBar createMenuBar()
  {
    final JMenuBar menu = new JMenuBar();
    menu.add(createFileMenu());
    menu.add(createEditMenu());
    menu.add(createViewMenu());
    menu.add(createWindowsMenu());
    attrDomainsMenu = new JMenu("Domains");
    attrDomainsMenu.setMnemonic(KeyEvent.VK_D);
    menu.add(attrDomainsMenu);
    createAttrDomainMenu(attrDomainsMenu);
    return menu;
  }
  /**
   * Create Attribute Domains menu
   *
   * @return the domain menu
   */
  private void createAttrDomainMenu(JMenu menu)
  {
    menu.removeAll();
    Collection<DynamicView> dynViews = dynamicViews.values();
    JMenuItem menuItem = new JMenuItem("Add Attribute Domain");
    menuItem.addActionListener(new ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        chooseAttributeDomain();
      }
    });
    menuItem.setMnemonic(KeyEvent.VK_A);
    menu.add(menuItem);
    if (dynViews.size()>0){
      menu.addSeparator();
      for (DynamicView dv : dynViews) {
        final DynamicView view = dv;
        menuItem = new JMenuItem(view.getTitle(), view.getIcon());
        menuItem.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e)
          {
            view.restoreFocus();
          }
        });
        menu.add(menuItem);
      }
    }
  }

  private void chooseAttributeDomain()
  {
    Vector<Domain> domains = DomainFactory.getPredefinedDomains();
    AddDomainDialog addDialog = new AddDomainDialog(this);
    Domain<?> d = addDialog.showDomainDialog(domains);
    if(d instanceof Parametrized){
      if(((Parametrized)d).getParameter() instanceof Integer){
        Integer value =(Integer)((Parametrized)d).getParameter();
        BoundedIntegerDialog dialog;
        if(d instanceof IntMinMax){
          dialog = new BoundedIntegerDialog(this,
            "Choose maximal skill level k");
        }
        else{
          dialog = new BoundedIntegerDialog(this,
            "Choose value for k");
        }
        BoundedInteger result =(BoundedInteger) (dialog.showInputDialog(new BoundedInteger(value,
                Integer.MAX_VALUE),false));
        if(result!=null){
          value = new Integer(result.getValue());
          if (value == BoundedInteger.INF){
            value = Integer.MAX_VALUE;
          }
          ((Parametrized)d).setParameter(value);
        }
        else {
          d=null;
        }
      }
    }
    if (d == null) {
      return;
    }
    else {
      addAttributeDomain(d);
      //if(s.equals("Custom")){
        //addCustomDomain(s);
      //}
      //else {
      //}
    }
  }
  private void addCustomDomain(String s)
  {
    System.err.println("Custom domains not implemented yet!");
  }
  /**
   * Add a predefined domain window.
   *
   * @param s
   */
  private Dimension getScreenSize(double scaleY, double scaleX)
  {
    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    GraphicsDevice[] gs = ge.getScreenDevices();
    DisplayMode dm = gs[0].getDisplayMode();
    return new Dimension((int)(dm.getWidth()*scaleX),(int)(dm.getHeight()*scaleY));
  }

  /**
   * Adds new attribute domain.
   * 
   * @param d
   */
  private void addAttributeDomain(Domain d)
  {
    View view = getDynamicView(getDynamicViewId(),d); 

    //updateViews((DockingWindow)view,true);
    FloatingWindow fw = rootWindow.createFloatingWindow(new Point(50,50),
                                                        getScreenSize(0.75,0.4), view);
    // Show the window
    ((Window)fw.getTopLevelAncestor()).setAlwaysOnTop(false);
    fw.getTopLevelAncestor().setVisible(true);
  }

  /**
   * Retrieves a DynamicView with domain.
   * 
   * @param id id of the view
   * @param s class name of the domain.
   * @return creater or retreived DynamicView.
   */
  private View getDynamicView(int id, Domain d){
    View view = (View) dynamicViews.get(new Integer(id));
    if (view == null){
      //Domain d = DomainFactory.createFromString(s);
      if (d != null){
        ADTreeForGui tree = ((ADTreeView)views[0].getComponent()).getTree();
        DomainView dv = new DomainView(tree,this,d,id);
        view = new DynamicView((1+id)+". "+d.getName(), dv.getIcon(), dv, id);
      }
    }
    return view;
  }

  /**
   * Creates the windows menu where not shown views can be shown.
   *
   * @return the view menu
   */
  private JMenu createWindowsMenu()
  {
    JMenu menu = new JMenu("Windows");
    menu.setMnemonic(KeyEvent.VK_W);

    for (int i = 0; i < views.length; i++) {
      final View view = views[i];
      windowsItems[i] = new JMenuItem(view.getTitle(), view.getIcon());
      windowsItems[i].setEnabled(views[i].getRootWindow() == null);
      menu.add(windowsItems[i]).addActionListener(new ActionListener()
      {
        public void actionPerformed(ActionEvent e)
        {
          if (view.getRootWindow() != null)
            view.restoreFocus();
          else {
            DockingUtil.addWindow(view, rootWindow);
          }
        }
      });
    }
    windowsItems[0].setMnemonic('r');
    windowsItems[1].setMnemonic('e');
    windowsItems[2].setMnemonic('V');
    windowsItems[3].setMnemonic('D');
    return menu;
  }
  private JMenu createEditMenu()
  {
    JMenuItem menuItem;
    final JMenu editMenu = new JMenu();
    editMenu.setText(ButtonTexts.EDIT);
    editMenu.setMnemonic('E');
    menuItem = new JMenuItem(new DefaultEditorKit.CutAction());
    menuItem.setText("Cut");
    menuItem.setMnemonic(KeyEvent.VK_T);
    menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X,
        InputEvent.CTRL_MASK));
    editMenu.add(menuItem);

    menuItem = new JMenuItem(new DefaultEditorKit.CopyAction());
    menuItem.setText("Copy");
    menuItem.setMnemonic(KeyEvent.VK_C);
    menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C,
        InputEvent.CTRL_MASK));
    editMenu.add(menuItem);

    menuItem = new JMenuItem(new DefaultEditorKit.PasteAction());
    menuItem.setText("Paste");
    menuItem.setMnemonic(KeyEvent.VK_P);
    menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V,
        InputEvent.CTRL_MASK));
    editMenu.add(menuItem);
    editMenu.addSeparator();
    menuItem = new JMenuItem("Switch Attacker/Defender roles");
    menuItem.addActionListener(new ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        Options.canv_Defender = Options.canv_Defender==ADTreeNode.Type.PROPONENT?
                                ADTreeNode.Type.OPPONENT:ADTreeNode.Type.PROPONENT;
        ((ADTreeView)views[0].getComponent()).getCanvas().repaint();
        for(View v:dynamicViews.values()){
          ((DomainView)v.getComponent()).getCanvas().repaint();
        }
      }
    });
    menuItem.setMnemonic(KeyEvent.VK_S);
    menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_W,
        InputEvent.CTRL_MASK));
    editMenu.add(menuItem);
    menuItem = new JMenuItem("Validate Terms");
    menuItem.addActionListener(new ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        ((ADTermView)views[1].getComponent()).parse();
      }
    });
    menuItem.setMnemonic(KeyEvent.VK_L);
    menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,
        InputEvent.CTRL_MASK));
    editMenu.add(menuItem);
    return editMenu;
  }
  /**
   * Creates the file menu.
   *
   * @return the file menu
   */
  private JMenu createFileMenu()
  {
    JMenuItem menuItem;
    final JMenu fileMenu = new JMenu();
    fileMenu.setText(ButtonTexts.FILE);
    fileMenu.setMnemonic('F');

    menuItem = fileMenu.add(fileNew);
    menuItem.addMouseListener(mouseHandler);
    fileMenu.add(menuItem);
    fileMenu.addSeparator();

    menuItem = fileMenu.add(fileOpen);
    menuItem.addMouseListener(mouseHandler);
    fileMenu.add(menuItem);

    menuItem = fileMenu.add(fileSave);
    menuItem.addMouseListener(mouseHandler);
    fileMenu.add(menuItem);

    menuItem = fileMenu.add(fileExample);
    menuItem.addMouseListener(mouseHandler);
    fileMenu.add(menuItem);

    JMenu exportTo = new JMenu("Export to");
    exportTo.setMnemonic(KeyEvent.VK_E);
    menuItem = exportTo.add(fileExportToPdf);
    menuItem.addMouseListener(mouseHandler);
    exportTo.add(menuItem);
    menuItem = exportTo.add(fileExportToLatex);
    menuItem.addMouseListener(mouseHandler);
    exportTo.add(menuItem);
    menuItem = exportTo.add(fileExportToPng);
    menuItem.addMouseListener(mouseHandler);
    exportTo.add(menuItem);
    menuItem = exportTo.add(fileExportToJpg);
    menuItem.addMouseListener(mouseHandler);
    exportTo.add(menuItem);
    fileMenu.add(exportTo);

    menuItem = fileMenu.add(filePrint);
    menuItem.addMouseListener(mouseHandler);
    fileMenu.add(menuItem);

    menuItem = fileMenu.add(filePrintPreview);
    menuItem.addMouseListener(mouseHandler);
    fileMenu.add(menuItem);

    menuItem = fileMenu.add(fileExit);
    menuItem.addMouseListener(mouseHandler);
    fileMenu.add(menuItem);
    return fileMenu;
  }
  /**
   * Create view menu.
   *
   * @return
   */
  private JMenu createViewMenu()
  {
    JMenu viewMenu = new JMenu("View");
    viewMenu.setMnemonic(KeyEvent.VK_V);
    JMenu themesMenu = new JMenu("Themes");
    themesMenu.setMnemonic(KeyEvent.VK_T);
    JMenu layoutMenu = new JMenu("Layouts");
    layoutMenu.setMnemonic(KeyEvent.VK_L);

    final RootWindowProperties titleBarStyleProperties = PropertiesUtil
        .createTitleBarStyleRootWindowProperties();

    final JCheckBoxMenuItem titleBarStyleItem = new JCheckBoxMenuItem(
        "Title Bar Style Theme");
    titleBarStyleItem.setSelected(false);
    titleBarStyleItem.addActionListener(new ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        if (titleBarStyleItem.isSelected())
          properties.addSuperObject(titleBarStyleProperties);
        else
          properties.removeSuperObject(titleBarStyleProperties);
      }
    });

    themesMenu.add(titleBarStyleItem);
    themesMenu.addSeparator();

    DockingWindowsTheme[] themes = { new DefaultDockingTheme(),
        new LookAndFeelDockingTheme(), new BlueHighlightDockingTheme(),
        new SlimFlatDockingTheme(), new GradientDockingTheme(),
        new ShapedGradientDockingTheme(), new SoftBlueIceDockingTheme(),
        new ClassicDockingTheme() };

    ButtonGroup group = new ButtonGroup();

    for (int i = 0; i < themes.length; i++) {
      final DockingWindowsTheme theme = themes[i];

      JRadioButtonMenuItem item = new JRadioButtonMenuItem(theme.getName());
      item.setSelected(i == 4);
      group.add(item);

      themesMenu.add(item).addActionListener(new ActionListener()
      {
        public void actionPerformed(ActionEvent e)
        {
          // Clear the modified properties values
          properties.getMap().clear(true);

          setTheme(theme);
        }
      });
    }
    viewMenu.add(themesMenu);
    JMenuItem menuItem;
    menuItem = new JMenuItem("Restore Default");
    menuItem.addActionListener(new ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        restoreDefaultLayout();
      }
    });
    menuItem.setMnemonic(KeyEvent.VK_D);
    layoutMenu.add(menuItem);
    layoutMenu.addSeparator();
    menuItem = new JMenuItem("Store in Memory");
    menuItem.addActionListener(new ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
          ObjectOutputStream out = new ObjectOutputStream(bos);
          rootWindow.write(out, false);
          out.close();
        }
        catch (IOException err) {
          System.err.println("Error serializing layout:" + err);
        }
        layout = bos.toByteArray();
      }
    });
    menuItem.setMnemonic(KeyEvent.VK_M);
    layoutMenu.add(menuItem);
    menuItem = new JMenuItem("Restore Layout");
    menuItem.addActionListener(new ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        SwingUtilities.invokeLater(new Runnable()
        {
          public void run()
          {
            if (layout != null) {
              try {
                // Load the layout from a byte array
                ObjectInputStream in = new ObjectInputStream(
                    new ByteArrayInputStream(layout));
                rootWindow.read(in, true);
                in.close();
              }
              catch (IOException e1) {
                throw new RuntimeException(e1);
              }
            }
          }
        });
      }
    });
    menuItem.setMnemonic(KeyEvent.VK_R);
    layoutMenu.add(menuItem);
    layoutMenu.addSeparator();
    menuItem = new JMenuItem("Save to File");
    menuItem.addActionListener(new ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        SwingUtilities.invokeLater(new Runnable()
        {
          public void run()
          {
            ObjectOutputStream out = fh.getSaveLayoutStream();
            if (out != null) {
              try {
                rootWindow.write(out, false);
                out.close();
              }
              catch (final IOException e2) {
                System.err.println("IO error:" + e2);
              }
            }
          }
        });
      }
    });
    menuItem.setMnemonic(KeyEvent.VK_S);
    layoutMenu.add(menuItem);
    menuItem = new JMenuItem("Load from File");
    menuItem.addActionListener(new ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        SwingUtilities.invokeLater(new Runnable()
        {
          public void run()
          {
            ObjectInputStream in = fh.getLoadLayoutStream();
            if (in != null) {
              try {
                rootWindow.read(in, true);
                in.close();
              }
              catch (final IOException e2) {
                System.err.println("IO error:" + e2);
              }
            }
          }
        });
      }
    });
    menuItem.setMnemonic(KeyEvent.VK_L);
    layoutMenu.add(menuItem);
    viewMenu.add(layoutMenu);
    menuItem = new JMenuItem("Expand all nodes");
    menuItem.addActionListener(new ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        ADTreeCanvas canvas = ((ADTreeView)views[0].getComponent()).getCanvas();
        canvas.expandAllNodes();
      }
    });
    menuItem.setMnemonic(KeyEvent.VK_E);
    viewMenu.add(menuItem);
    menuItem = new JMenuItem("Fit to window");
    menuItem.addActionListener(new ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        ADTreeCanvas canvas = ((ADTreeView)views[0].getComponent()).getCanvas();
        if (lastFocused != null) {
          canvas = lastFocused;
        }
        canvas.fitToWindow();
      }
    });
    menuItem.setMnemonic(KeyEvent.VK_F);
    viewMenu.add(menuItem);
    return viewMenu;
  }

  /**
   * ADAction represents an action that is used in application.
   */
  public abstract class ADAction extends AbstractAction
  {
    /**
     * Defines an ADAction object with the specified descripiton and a default
     * icon.
     * @param text text to be displayed
     */
    public ADAction(final String text)
    {
      super(text);
    }

    /**
     * Sets accelerator for the action.
     *
     * @param accelerator
     *          new accelerator
     */
    public final void setAccelerator(final KeyStroke accelerator)
    {
      putValue(ACCELERATOR_KEY, accelerator);
    }

    /**
     * Sets the new small icon for the action.
     *
     * @param icon new icon
     */
    public final void setSmallIcon(final Icon icon)
    {
      putValue(SMALL_ICON, icon);
    }
    /**
     * Sets tooltip for the action.
     *
     * @param text
     *          new tooltip text
     */
    public final void setToolTip(final String text)
    {
      putValue(SHORT_DESCRIPTION, text);
    }

    /**
     * Sets long description for the action.
     * @param text
     */
    public final void setDescription(final String text)
    {
      putValue(LONG_DESCRIPTION, text);
    }

    /**
     * Sets mnemonic for the action.
     * @param mnemonic new mnemonic
     */
    public final void setMnemonic(final Integer mnemonic)
    {
      putValue(MNEMONIC_KEY, mnemonic);
    }

    /**
     * {@inheritDoc}
     * @see ActionListener#actionPerformed(ActionEvent)
     */
    public abstract void actionPerformed(final ActionEvent e);
  }

  /**
   * Sets the docking windows theme.
   *
   * @param theme the docking windows theme
   */
  private void setTheme(DockingWindowsTheme theme) {
    properties.replaceSuperObject(currentTheme.getRootWindowProperties(),
                                  theme.getRootWindowProperties());
    currentTheme = theme;
  }

  /**
   * This adapter is constructed to handle mouse over component events.
   */
  private class MouseHandler extends MouseAdapter
  {

    private JLabel label;

    /**
     * ctor for the adapter.
     *
     * @param label
     *          the JLabel which will recieve value of the
     *          Action.LONG_DESCRIPTION key.
     */
    public MouseHandler(JLabel label)
    {
      setLabel(label);
    }

    public void setLabel(JLabel label)
    {
      this.label = label;
    }

    public void mouseEntered(MouseEvent evt)
    {
      if (evt.getSource() instanceof AbstractButton) {
        AbstractButton button = (AbstractButton) evt.getSource();
        Action action = button.getAction(); // getAction is new in JDK 1.3
        if (action != null) {
          String message = (String) action.getValue(Action.LONG_DESCRIPTION);
          label.setText(message);
        }
      }
    }
  }
  /**
   * Loads the example tree and attribute domains.
   * 
   */
  private void loadExample()
  {
    LoadExampleDialog dialog = new LoadExampleDialog(this);
    String fileName = dialog.showDialog(); 
    if(fileName!= null){
      try{
        URL url = this.getClass().getResource(fileName);
        InputStream in = url.openStream();
        loadFromStreamTree(new ObjectInputStream(in));
      }
      catch(IOException e){
        System.err.println("Error loading example tree.");
      }
    }
  }
  private void loadFromStreamTree(ObjectInputStream in){
    if (in != null) {
      try {
        ADTreeNode root = (ADTreeNode)in.readObject();
        Map<ADTreeNode, List<ADTreeNode>> childrenMap =(Map<ADTreeNode, List<ADTreeNode>>)in.readObject();
        Map<ADTreeNode, ADTreeNode>       parents     = (Map<ADTreeNode, ADTreeNode>)in.readObject();
        int maxCounter = 0;
        for(ADTreeNode node:parents.keySet()){
          maxCounter = Math.max(maxCounter,node.getId());
          if(node.isAboveFolded()){
            node.setAboveFolded(false);
          }
        }
        ADTreeNode.resetCounter(maxCounter+1);
        ((ADTreeView)views[0].getComponent()).getCanvas().setFocus(null);
        ADTreeForGui newTree = new ADTreeForGui(root,childrenMap,parents);
        //((ADTreeView)views[0].getComponent()).getCanvas().newTree();
        views[0].setComponent(new ADTreeView(newTree,this));
        ADTreeCanvas canvas = ((ADTreeView)views[0].getComponent()).getCanvas();
        views[1].setComponent(new ADTermView(canvas));
        views[2].setComponent(new ValuationView());
        views[3].setComponent(new DetailsView());
        Options.canv_BackgroundColor = (Color)in.readObject();
        Options.canv_EdgesColor    = (Color)in.readObject();
        Options.canv_TextColorAtt  = (Color)in.readObject();
        Options.canv_TextColorDef  = (Color)in.readObject();
        Options.canv_FillColorAtt  = (Color)in.readObject();
        Options.canv_FillColorDef  = (Color)in.readObject();
        Options.canv_BorderColorAtt= (Color)in.readObject();
        Options.canv_BorderColorDef= (Color)in.readObject();
        Options.canv_EditableColor = (Color)in.readObject();
        Options.canv_ShapeAtt      = (Options.ShapeType)in.readObject();
        Options.canv_ShapeDef      = (Options.ShapeType)in.readObject();
        Options.canv_Font          = (Font)in.readObject();
        Options.canv_Defender      = (ADTreeNode.Type)in.readObject();
        Options.canv_ArcSize       = (Integer)in.readObject();
        Options.canv_ArcPadding    = (Integer)in.readObject();
        Options.canv_LineWidth     = (Integer)in.readObject();
        Options.canv_DoAntialiasing= (Boolean)in.readObject();
        Boolean savedLayout = (Boolean)in.readObject();
        if (savedLayout){
          rootWindow.read(in, true);
        }
        else{
          for(View v:dynamicViews.values()){
            v.close();
          }
        }
        Integer noDomains = (Integer)in.readObject();
        for(int i = 0; i < noDomains; i++){
          Domain<?>  d = (Domain<?>)in.readObject();
          ValueAssignement vass = (ValueAssignement)in.readObject();
          View view = getDynamicView(i,d);
          ((DomainView<?>) view.getComponent()).getCanvas().setValueAssPro(vass);
          vass = (ValueAssignement)in.readObject();
          ((DomainView<?>) view.getComponent()).getCanvas().setValueAssOpp(vass);
          if (!savedLayout){
            FloatingWindow fw = rootWindow.createFloatingWindow(new Point(50, 50),
                                                        getScreenSize(0.75,0.4),
                                                        view);
            ((Frame)fw.getTopLevelAncestor()).setAlwaysOnTop(false);
           // Show the window
           fw.getTopLevelAncestor().setVisible(true);
          }
        }
        newTree.updateAllSizes();
        in.close();
      }
      catch (final IOException e) {
        System.err.println("IO error:" + e);
      }
      catch(ClassNotFoundException ex)
      {
        ex.printStackTrace();
      }
    }
  }
  /**
   * Loads the tree and attribute domains.
   * 
   */
  private void loadTree()
  {
    ObjectInputStream in = fh.getLoadTreeStream();
    loadFromStreamTree(in);
  }

  /**
   * Saves the tree and attribute domains.
   * 
   */
  private void saveTree()
  {
    ObjectOutputStream out = fh.getSaveTreeStream();
    if (out != null) {
      try {
        ADTreeForGui tree = ((ADTreeView) views[0].getComponent()).getCanvas()
            .getTree();
        out.writeObject(tree.getRoot(true));
        out.writeObject(tree.getChildrenMap());
        out.writeObject(tree.getParents());
        out.writeObject(Options.canv_BackgroundColor);
        out.writeObject(Options.canv_EdgesColor);
        out.writeObject(Options.canv_TextColorAtt);
        out.writeObject(Options.canv_TextColorDef);
        out.writeObject(Options.canv_FillColorAtt);
        out.writeObject(Options.canv_FillColorDef);
        out.writeObject(Options.canv_BorderColorAtt);
        out.writeObject(Options.canv_BorderColorDef);
        out.writeObject(Options.canv_EditableColor);
        out.writeObject(Options.canv_ShapeAtt);
        out.writeObject(Options.canv_ShapeDef);
        out.writeObject(Options.canv_Font);
        out.writeObject(Options.canv_Defender);
        out.writeObject(Options.canv_ArcSize);
        out.writeObject(Options.canv_ArcPadding);
        out.writeObject(Options.canv_LineWidth);
        out.writeObject(Options.canv_DoAntialiasing);
        out.writeObject(new Boolean(Options.main_saveLayout));
        if (Options.main_saveLayout) {
          rootWindow.write(out, false);
        }
        out.writeObject(new Integer(dynamicViews.size()));
        for (View v : dynamicViews.values()) {
          out.writeObject(((DomainView) v.getComponent()).getCanvas()
              .getDomain());
          out.writeObject(((DomainView) v.getComponent()).getCanvas()
              .getValueAssPro());
          out.writeObject(((DomainView) v.getComponent()).getCanvas()
              .getValueAssOpp());
        }
        out.close();
      }
      catch (final IOException e2) {
        System.err.println("IO error:" + e2);
      }
    }
  }

  /**
   * Detect if application is run using JWS.
   * 
   * @return true if we run under JWS.
   */
  private boolean isRunningJavaWebStart()
  {
    return System.getProperty("javawebstart.version", null) != null;
  }
}
